import { URI } from "vscode-uri";
import { DendronGlobalConfig } from ".";
import { DVault } from "./DVault";

export interface Point {
  /**
   * Line in a source file (1-indexed integer).
   */
  line: number;

  /**
   * Column in a source file (1-indexed integer).
   */
  column: number;
  /**
   * Character in a source file (0-indexed integer).
   */
  offset?: number;
}

export interface Position {
  /**
   * Place of the first character of the parsed source region.
   */
  start: Point;

  /**
   * Place of the first character after the parsed source region.
   */
  end: Point;

  /**
   * Start column at each index (plus start line) in the source region,
   * for elements that span multiple lines.
   */
  indent?: number[];
}

export type DLoc = {
  fname?: string;
  id?: string;
  vaultName?: string;
  uri?: URI;
  anchorHeader?: string;
};

/**
 @deprecated use {@link DNoteLink}
 */
export type DLink = {
  type: "ref" | "wiki" | "md" | "backlink" | "linkCandidate" | "frontmatterTag";
  value: string;
  alias?: string;
  position?: Position;
  from: DLoc;
  to?: DLoc;
  xvault?: boolean;
  /** Denotes a same file link, for example `[[#anchor]]` */
  sameFile?: boolean;
};

export type DNodeType = "note" | "schema";
export type DNodePointer = string;
export type DNodeImage = { url: string; alt: string };

/**
 * Notes have a config property that can override a subset of {@link dendronConfig}
 */
export type NoteLocalConfig = Partial<{
  global: Partial<
    Pick<
      DendronGlobalConfig,
      "enableChildLinks" | "enablePrettyRefs" | "enableBackLinks"
    >
  >;
}>;
export type DNodeAllProps = DNodeExplicitPropsEnum & DNodeImplicitPropsEnum;

/**
 * Node property keys that are written to the frontmatter
 */
export enum DNodeExplicitPropsEnum {
  id = "id",
  title = "title",
  desc = "desc",
  updated = "updated",
  created = "created",
  config = "config",
  color = "color",
  tags = "tags",
  traitIds = "traitIds",
  image = "image",
}

/**
 * Node property keys that are not written to the frontmatter
 */
export enum DNodeImplicitPropsEnum {
  fname = "fname",
  parent = "parent",
  children = "children",
  body = "body",
  data = "data",
  schemaStub = "schemaStub",
  type = "type",
  custom = "custom",
  links = "links",
}

/**
 * Node property keys that are written to the frontmatter
 */
export type DNodeExplicitProps = {
  /**
   * Unique id of a note
   */
  id: string;
  /**
   * Node title
   */
  title: string;
  /**
   * Node description
   */
  desc: string;
  /**
   * Last updated
   */
  updated: number;
  /**
   * Created
   */
  created: number;
  /**
   * Override of local dendron config
   */
  config?: NoteLocalConfig;
};

/**
 * Props are the official interface for a node
 */
export type DNodeProps<T = any, TCustom = any> = DNodeExplicitProps & {
  /**
   * Name of the node. This corresponds to the name of the file minus the extension
   */
  fname: string;
  /**
   * Node links (eg. backlinks, wikilinks, etc)
   */
  links: DLink[];
  /**
   * Anchors within the node (headings, block anchors)
   */
  anchors: { [index: string]: DNoteAnchorPositioned | undefined };
  /**
   * Whether this node is a note or a schema
   */
  type: DNodeType;
  /**
   * Determines whether this node is a {@link stub https://wiki.dendron.so/notes/c6fd6bc4-7f75-4cbb-8f34-f7b99bfe2d50.html#stubs}
   */
  stub?: boolean;
  /**
   @deprecated
   */
  schemaStub?: boolean;
  /**
   * Immediate parent
   */
  parent: DNodePointer | null;
  /**
   * Immediate children
   */
  children: DNodePointer[];
  data: T;
  /**
   * Body of the note
   */
  body: string;
  /**
   * Custom frontmatter. Add additional fields here and they will show up in the note frontmatter
   */
  custom?: TCustom;
  /**
   * Schemas that apply to the note
   */
  schema?: { moduleId: string; schemaId: string };
  /**
   * The vault that a note belongs to
   */
  vault: DVault;

  /**
   * Hash of note content
   */
  contentHash?: string;

  /** Override the randomly generated color for tag notes. Colors can be entered as `#12AC35`, `rgb(123, 56, 200)`, or `hsl(235, 100%, 50%)`. */
  color?: string;

  /** One or more frontmatter tags attached to this note. */
  tags?: string | string[];

  /** To be used by social media platforms as a thumbnail/preview. */
  image?: DNodeImage;

  /** Any note traits that add special behavior to the note */
  traits?: string[];
};

export type DNodeCompositeKey = Pick<DNodeProps, "fname"> & {
  vaultName?: string;
};

export type SchemaData = {
  namespace?: boolean;
  pattern?: string;
  template?: SchemaTemplate;
  isIdAutoGenerated?: boolean;
  desc?: string;
};

export type SchemaTemplate = {
  id: string;
  type: "snippet" | "note";
};

export type SchemaProps = DNodeProps<SchemaData>;
/**
 * Interface for a Dendron Note
 */
export type NoteProps = DNodeProps<any, any>;

/**
 * Dendron note metadata
 */
export type NotePropsMeta = Omit<NoteProps, "body">;

/**
 * Dendron note with optional custom props
 */
export type NotePropsWithOptionalCustom = Omit<NoteProps, "custom"> &
  Partial<{ custom: any }>;

export type SEOProps = {
  title: string;
  updated: number;
  created: number;
  excerpt?: string;
  description?: string;
  image?: DNodeImage;
  /**
   * Use as root canonical url for all published notes
   */
  canonicalBaseUrl?: string;
  canonicalUrl?: string;
  noindex?: boolean;
  twitter?: string;
};

export type DNoteLoc = {
  fname: string;
  alias?: string;
  id?: string;
  vaultName?: string;
  anchorHeader?: string;
};

export type DNoteAnchor =
  | DNoteBlockAnchor
  | DNoteHeaderAnchor
  | DNoteLineAnchor;

/**
 * Anchor without {@link DNoteHeaderAnchor.depth} info
 * @todo see migration [[DNoteAnchorBasic|dendron://dendron.docs/dev.changelog#dnoteanchorbasic]]
 */
export type DNoteAnchorBasic =
  | DNoteBlockAnchor
  | Omit<DNoteHeaderAnchor, "depth">
  | DNoteLineAnchor;

export type DNoteBlockAnchor = {
  type: "block";
  text?: string; //original text for the anchor
  value: string;
};

/**
 * This represents a markdown header
 * ```md
 * # H1
 * ```
 */
export type DNoteHeaderAnchor = {
  type: "header";
  text?: string; //original text for the anchor
  value: string;
  depth: number;
};

/** An anchor referring to a specific line in a file. These don't exist inside of files, they are implied by the link containing the anchor.
 *
 * Lines are indexed starting at 1, which is similar to how you refer to specific lines on Github.
 */
export type DNoteLineAnchor = {
  type: "line";
  /** 1-indexed line number. */
  line: number;
  value: string;
};

export type DNoteAnchorPositioned = (DNoteBlockAnchor | DNoteHeaderAnchor) & {
  line: number;
  column: number;
};
